package com.github.base.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.lang.tree.parser.NodeParser;
import cn.hutool.core.util.ObjectUtil;
import com.github.base.domain.Permission;
import com.github.base.domain.RolePermission;
import com.github.base.dto.permission.PermissionDTO;
import com.github.base.dto.permission.PermissionMoveDTO;
import com.github.base.global.Const;
import com.github.base.mapper.PermissionMapper;
import com.github.base.mapper.RolePermissionMapper;
import com.github.base.service.PermissionService;
import com.github.base.utils.Result;
import com.github.base.vo.permission.PermissionVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: base
 * @description: 权限
 * @author: hui.zhang
 * @date: 2021/1/27 5:06 下午
 **/

@Slf4j
@Service
@SuppressWarnings("all")
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    @Autowired
    private HttpServletRequest request;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(PermissionDTO dto) {
        // 设置排序
        Long parentId = dto.getParentId();
        LambdaQueryWrapper<Permission> select = new QueryWrapper<Permission>().lambda().select(Permission::getId);
        select.eq(Permission::getParentId, parentId);
        Long count = permissionMapper.selectCount(select);

        Permission permission = BeanUtil.copyProperties(dto, Permission.class);
        // 如果是菜单 权限编码也为菜单作为标记
        if (Const.MENU.equals(dto.getPermissionType())) {
            permission.setPermissionCode(dto.getMenuUrl());
        }
        permission.setCreateTime(LocalDateTime.now());
        permission.setModifyTime(LocalDateTime.now());
        permission.setUsable(Const.YES);
        permission.setOperable(Const.YES);
        permission.setState(Const.YES);
        permission.setSortNumber(count.intValue() + 1);
        permission.insert();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteById(Long id) {
        // 先判断子级有没有数据
        LambdaQueryWrapper<Permission> wrapper = new QueryWrapper<Permission>().lambda().select(Permission::getId);
        wrapper.eq(Permission::getParentId, id).eq(Permission::getState, Const.YES);
        Long count = permissionMapper.selectCount(wrapper);
        if (count > 0) {
            throw new RuntimeException("存在子资源，不能直接删除");
        }

        // 判断有没有角色绑定
        LambdaQueryWrapper<RolePermission> select = new QueryWrapper<RolePermission>().lambda();
        select.eq(RolePermission::getPermissionId, id);
        Long roleBindingCount = rolePermissionMapper.selectCount(select);
        if (roleBindingCount > 0) {
            throw new RuntimeException("有角色绑定，不能直接删除");
        }

        Permission permission = new Permission();
        permission.setId(id);
        permission.setState(Const.NO);
        permission.setModifyTime(LocalDateTime.now());
        permissionMapper.updateById(permission);
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(PermissionDTO dto) {
        Permission permission = new Permission();
        BeanUtil.copyProperties(dto, permission);
        // 如果是菜单 权限编码也为菜单作为标记
        if (Const.MENU.equals(dto.getPermissionType())) {
            permission.setPermissionCode(dto.getMenuUrl());
        }
        permission.setModifyTime(LocalDateTime.now());
        permission.updateById();
    }

    @Override
    public Result<List<Tree<Long>>> getTree() {
        LambdaQueryWrapper<Permission> wrapper = new QueryWrapper<Permission>().lambda().eq(Permission::getState, Const.YES);
        wrapper.orderByAsc(Permission::getSortNumber);
        List<Permission> permissions = permissionMapper.selectList(wrapper);
        List<Tree<Long>> trees = TreeUtil.build(permissions, 0L, new NodeParser<Permission, Long>() {
            @Override
            public void parse(Permission permission, Tree<Long> tree) {
                tree.setId(permission.getId());
                tree.setParentId(permission.getParentId());
                tree.setName(permission.getPermissionName());
                tree.putExtra("permissionType", permission.getPermissionType());
                tree.putExtra("menuIcon", permission.getMenuIcon());
                tree.putExtra("menuUrl", permission.getMenuUrl());
                tree.putExtra("sortNumber", permission.getSortNumber());
                tree.putExtra("operable", permission.getOperable());
                tree.put("permissionCode", permission.getPermissionCode());
            }
        });
        return Result.ok(trees);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void move(PermissionMoveDTO dto) {
        Integer fId = dto.getFId();
        Integer sId = dto.getSId();
        Permission up = permissionMapper.selectById(fId);
        Permission down = permissionMapper.selectById(sId);
        if (ObjectUtil.isEmpty(up) || ObjectUtil.isEmpty(down)) {
            throw new RuntimeException("移动数据不存在");
        }
        if (!up.getParentId().equals(down.getParentId())) {
            throw new RuntimeException("不能非同级移动");
        }
        Integer upSortNumber = up.getSortNumber();
        Integer downSortNumber = down.getSortNumber();
        up.setSortNumber(downSortNumber);
        down.setSortNumber(upSortNumber);
        List<Permission> list = new ArrayList<>();
        list.add(up);
        list.add(down);
        this.updateBatchById(list);
    }


    @Override
    public List<PermissionVO> currentInfo() {
        long userId = StpUtil.getLoginIdAsLong();
        List<PermissionVO> list = permissionMapper.findPermissionsByUserId(userId);
        return list;
//        List<Tree<Long>> trees = TreeUtil.build(list, 0L, new NodeParser<PermissionVO, Long>() {
//            @Override
//            public void parse(PermissionVO p, Tree<Long> tree) {
//                tree.setId(p.getId());
//                tree.setParentId(p.getParentId());
//                tree.setName(p.getPermissionName());
//                tree.putExtra("permissionType", p.getPermissionType());
//                tree.putExtra("menuIcon", p.getMenuIcon());
//                tree.putExtra("menuUrl", p.getMenuUrl());
//                tree.putExtra("sortNumber", p.getSortNumber());
//                tree.putExtra("operable", p.getOperable());
//                tree.putExtra("permissionCode", p.getPermissionCode());
//            }
//        });
//        return Result.ok(trees);
    }
}
